package com.sniper.springmvc.shiro.session.redis;

import org.apache.shiro.cache.CacheException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;

/**
 * redis缓存处理
 *
 * @author suzhen
 */
public class RedisSessionDAO extends AbstractSessionDAO {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisSessionDAO.class);
    //定义储存结构，key 是byte Value session 在最后储存中Value都会被转成byte结构，所以key推荐byte[]
    private MyCache<byte[], Session> cache;


    public RedisSessionDAO() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        //随便起个名字
        cache = redisCacheManager.getCache("redis");
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        saveSession(sessionId, session);
        return sessionId;
    }

    /**
     * 用于储存更新session
     *
     * @param sessionId
     * @param session
     */
    private void saveSession(Serializable sessionId, Session session) {
        if (sessionId == null) {
            throw new NullPointerException("id argument cannot be null.");
        }
        try {
            byte[] names = this.getKey(session);
            cache.put(names, session, session.getTimeout());
        } catch (Exception e) {
            // 释放redis对象
            LOGGER.error("redis保存出错", e);
            e.printStackTrace();
        } finally {
        }
    }

    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
        return this.doReadSession(sessionId);
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            throw new NullPointerException("id argument cannot be null.");
        }
        try {
            byte[] names = this.getKeyString(sessionId.toString());
            Session session = cache.get(names);
            return session;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        return null;
    }

    @Override
    public Collection<Session> getActiveSessions() {

        Set<byte[]> keys = cache.keys();

        try {
            if (!CollectionUtils.isEmpty(keys)) {
                List<Session> values = new ArrayList<>(keys.size());
                for (byte[] key : keys) {
                    Session value = cache.get(key);
                    if (value != null) {
                        values.add(value);
                    }
                }
                return Collections.unmodifiableList(values);
            }

        } catch (Throwable t) {
            throw new CacheException(t);
        }

        return Collections.emptyList();
    }

    /**
     * 转移key
     *
     * @param session
     * @return
     */
    private byte[] getKey(Session session) {
        return session.getId().toString().getBytes();
    }

    private byte[] getKeyString(String id) {
        return id.getBytes();
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session.getId(), session);
    }

    @Override
    public void delete(Session session) {
        if (session == null) {
            throw new NullPointerException("session argument cannot be null.");
        }

        String id = session.getId().toString();

        cache.remove(this.getKeyString(id));
    }
}